package com.task.core.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.annotation.Resource;

import com.task.common.constant.ErrorCodeConstants;
import com.task.common.enums.*;
import com.task.common.info.QuestionShowInfo;
import com.task.common.redis.RedisKeyConstants;
import com.task.core.domain.*;
import com.task.core.domain.info.DataAvailableDataInfo;
import com.task.core.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.task.common.core.redis.RedisCache;
import com.task.common.domain.info.CountryInfo;
import com.task.common.exception.ServiceException;
import com.task.common.info.DeviceGroupInfo;
import com.task.common.utils.StringUtils;
import com.task.common.utils.SystemFunctionUtil;
import com.task.common.utils.constants.RedisConstants;
import com.task.common.utils.date.DateConstants;
import com.task.common.utils.date.DateUtil;
import com.task.common.utils.uuid.UUID;
import com.task.common.domain.info.PlanInfo;
import com.task.core.domain.info.PlanJsonConfig;
import com.task.core.domain.info.SourceConfig;
import com.task.core.dto.request.ClientMissionCompleteRequestDTO;
import com.task.core.dto.request.MissionGetRequestDTO;
import com.task.core.dto.response.DataOperationResponseDTO;
import com.task.core.dto.response.MissionOperationResponseDTO;
import com.task.core.mapper.ClientMapper;
import com.task.core.mapper.MissionMapper;
import com.task.core.test.WeightedRandomSelector;
import com.task.core.test.WeightedRandomSelector.Entry;

/**
 * @author 迪迦.
 * @date 2024/12/24 15:21
 */
@Service
@Slf4j
public class ClientServiceImpl implements ClientService {

  @Resource
  private ClientMapper clientMapper;

  @Resource
  private DeviceService deviceService;

  @Resource
  private DeviceGroupService deviceGroupService;

  @Resource
  private MissionService missionService;

  @Resource
  private DataOperationService dataOperationService;

  @Resource
  private MissionMapper missionMapper;

  @Resource
  private SendHistoryService sendHistoryService;

  @Resource
  private PlanService planService;

  @Resource
  private DatasourceService datasourceService;

  @Resource
  private RefererSourceService refererSourceService;

  @Resource
  private RedisCache redisService;

  @Resource
  private EngineService engineService;

  @Resource
  private EngineSchemeService engineSchemeService;

  @Resource
  private DataPreAvailableService dataPreAvailableService;

  @Resource
  private DataSendByMissionService dataSendByMissionService;

  @Resource
  private DataOperationInfoService dataOperationInfoService;

  @Resource
  private QuestionInfoService questionInfoService;


  public static final String DATA_SEND_MISSION_CODE = "missionCode";
  public static final String DATA_SEND_TYPE = "dateType";
  //用作索引表和详情表的code,后续更新删除使用
  public static final String DATA_SEND_INDEX_TABLE_CODE = "indexTableCode";
  //数据发送时间,yyyyMM,用作查找在哪张详情表中,mission表也在用
  public static final String DATA_SEND_TIME = "dataSendTime";
  public static final String DATA_SEND_T_NUM = "tNum";
  public static final String DATA_SEND_ID = "dataId";
  public static final String DATA_SEND_CODE = "dataCode";
  public static final String DATA_SEND_DATA_SOURCE_CODE = "sourceCode";
  public static final String DATA_SEND_DATA_SOURCE_DUPLICATE_CONDITION = "duplicateCondition";
  public static final String DATA_SEND_MISSION_NAME = "missionName";
  //public static final String DATA_SEND_MISSION_ID = "missionId";
  public static final String DATA_SEND_REDIS_KEY = "DATA_SEND_REDIS_KEY:";
  public static final String DATA_SEND_CHECK_REPEAT = "DATA_SEND_CHECK_REPEAT:";

  public static final String MISSION_SEND_WEEK = "week";
  public static final String MISSION_SEND_HOUR = "hour";
  public static final String MISSION_SEND_DAY = "day";
  public static final String MISSION_SEND_MISSION_CODE = "missionCode";
  public static final String MISSION_SEND_DEVICE_CODE = "deviceCode";
  public static final String MISSION_SEND_DEVICE_TYPE = "deviceType";
  //任务失败次数配置
  public static final String PAGE_STATUS_THRESHOLD = "pageStatusThreshold";
  public static final String MISSION_SEND_MISSION_ID = "missionId";
  //任务发送时的具体时间  date类型
  public static final String MISSION_SEND_DATE = "missionSendDate";
  public static final String MISSION_SEND_CODE = "missionSendCode";
  public static final String MISSION_SEND_REDIS_KEY = "MISSION_SEND_REDIS_KEY:";
  public static final String MISSION_SEND_CHECK_REPEAT = "MISSION_SEND_CHECK_REPEAT:";

  public static final String DATA_GET_LOCK = "DATA_GET_LOCK:";
  public static final String DEVICE_GET_LOCK = "DEVICE_GET_LOCK:";
  public static final String DATA_GET_LOCK_VALUE = "dataGetLockValue";
  public static final String TABLE_GET_LOCK_VALUE = "tableGetLockValue";


  @Override
  public DeviceInfo getDeviceByName(String deviceName, String authentication) {
    Long deptCode = clientMapper.getDeptId(authentication);
    DeviceInfo deviceByName = deviceService.getDeviceByName(deviceName, deptCode);
    if (ObjectUtils.isEmpty(deviceByName) || StringUtils.isEmpty(deviceByName.getCode())) {
      throw new ServiceException("设备未找到");
    }
    //if (Boolean.FALSE.equals(redisService.redisTemplate.opsForValue()
    //    .setIfAbsent(DEVICE_GET_LOCK + deviceByName.getCode(), 1, 30, TimeUnit.MINUTES))) {
    //  throw new ServiceException("设备已在使用状态");
    //}
    return deviceByName;
  }


  @Override
//  @Transactional
  public DataOperationResponseDTO getDataByMissionCode(String missionSessionCode, String dataType) {
    Map<String, Object> missionSendDetail = redisService.getCacheObject(
        MISSION_SEND_REDIS_KEY + missionSessionCode);
    if (ObjectUtils.isEmpty(missionSendDetail)) {
      throw new ServiceException("missionSessionCode 无效");
    }
    if (!DataFileTypeEnum.checkDataType(dataType)) {
      throw new ServiceException("dataType 无效");
    }
    String missionCode = missionSendDetail.get(MISSION_SEND_MISSION_CODE).toString();
    //获取完整的任务信息
    MissionInfo  missionByCode = missionService.getMissionByCode(missionCode, true);
    if (ObjectUtils.isEmpty(missionByCode)) {
      throw new ServiceException("任务不存在");
    }
    //获取计划,判断当前时间是否超过阈值
    if (StringUtils.isEmpty(missionByCode.getPlanCode())) {
      throw new ServiceException("任务计划为空");
    }
    //先获取所有索引表表名
    List<String> indexTableNameList = sendHistoryService.getIndexTableNameByPrefix(
        SystemFunctionUtil.HISTORY_DATA_GET_INDEX);
    if (CollectionUtils.isEmpty(indexTableNameList)) {
      throw new ServiceException("记录表为空,联系管理员");
    }
    Map<String, Object> sendDataMap = new HashMap<>();
    //随机选择一条sourceCode作为数据来源
    SourceConfig sourceConfig = getChooseSource(missionByCode, dataType);

    DataOperationInfo data = null;
    DataAvailableDataInfo dataAvailableDataInfo = getCanUseDataId(sourceConfig, missionByCode, dataType, indexTableNameList, sendDataMap);
    if(!ObjectUtils.isEmpty(dataAvailableDataInfo)){
      data = dataAvailableDataInfo.getDataOperationInfo();
    }

    //用作索引表和详情表的code,后续更新删除使用
    String indexTableCode = UUID.randomUUID().toString().replace("-", "");
    Date now = new Date();
    String dateFormat = DateUtil.dateToStr(now, DateConstants.DATE_FORMAT_YM);
    String dateFormatYmdHms = DateUtil.dateToStr(new Date(), DateConstants.DATE_TIME_FORMAT_NUM);
    String sendCode = UUID.randomUUID().toString().replace("-", "");
    if (!ObjectUtils.isEmpty(data)) {
      //将数据状态改为已使用
      dataOperationService.changeDataStatusById(data.getCode(), true, SystemFunctionUtil.getDistributeTableNameById(data.getId(), dataType,false),
          sourceConfig.getChooseCode(), dataType);
      DeviceInfo deviceInfo = deviceService.getDeviceByCode(missionSendDetail.get(MISSION_SEND_DEVICE_CODE).toString());
      insertDataGetHistory(data, missionByCode, dataType, deviceInfo, sourceConfig, indexTableCode, dateFormat, dateFormatYmdHms, sendCode, missionSessionCode);

      //向关系表插入数据
      dataOperationInfoService.insertDataToRelation(indexTableCode,data,missionByCode,dataType,sourceConfig);
      dataPreAvailableService.updateOrInsertPreAvailableData(dataAvailableDataInfo,missionByCode.getCode(),missionByCode.getAffiliateCode(),missionByCode.getAdvertiserCode(),dataType);


    }
    //将发送记录存到redis中,方便后续使用其他关联数据
    //sendDataMap.put(DATA_SEND_MISSION_ID, missionByCode.getId());
    sendDataMap.put(DATA_SEND_MISSION_CODE, missionByCode.getCode());
    sendDataMap.put(DATA_SEND_TYPE, dataType);
    sendDataMap.put(DATA_SEND_TIME, dateFormat);
    sendDataMap.put(DATA_SEND_INDEX_TABLE_CODE, indexTableCode);
    sendDataMap.put(DATA_SEND_ID, data.getId());
    sendDataMap.put(MISSION_SEND_CODE, missionSessionCode);
    sendDataMap.put(DATA_SEND_CODE, data.getCode());
    sendDataMap.put(DATA_SEND_DATA_SOURCE_CODE, sourceConfig.getChooseCode());
    sendDataMap.put(DATA_SEND_DATA_SOURCE_DUPLICATE_CONDITION, sourceConfig.getDuplicateCondition());
    sendDataMap.put(DATA_SEND_MISSION_NAME, missionByCode.getMissionName());
    redisService.setCacheObject(DATA_SEND_REDIS_KEY + sendCode, sendDataMap, 30, TimeUnit.MINUTES);
    return new DataOperationResponseDTO(data.getDataContent(), sendCode, data.getId());
  }

  private void insertDataGetHistory(DataOperationInfo data, MissionInfo mission,
      String dataType, DeviceInfo deviceInfo, SourceConfig sourceConfig, String indexTableCode,
      String dateFormat, String dateFormatYmdHms, String sendCode, String missionSessionCode) {
    //存索引表
    dataOperationService.insertHistoryDataGetIndex(mission, data.getCode(), indexTableCode,
        dateFormat, sourceConfig);

    //存详情表
    dataOperationService.insertHistoryDataGetDetail(data, mission, dataType, deviceInfo, dateFormat,
        indexTableCode, dateFormatYmdHms, sendCode, missionSessionCode);

    //任务和数据源关联表使用次数加1
    //这张表查询次数不会在逻辑运算里面,先试试直接每次操作数据库,应该没问题,有问题就挪到redis中定时任务更新
    if (DataFileTypeEnum.DATA.name().equals(dataType)) {
      //暂时只有datasource的数据需要加+
      missionService.incrementMissionAndSourceUseCountBySourceCode(mission.getCode(), sourceConfig.getChooseCode());
    }
  }

  private SourceConfig getChooseSource(MissionInfo mission, String dataType) {
    SourceConfig sourceConfig;
    if (DataFileTypeEnum.DATA.name().equals(dataType)) {
      if (StringUtils.isEmpty(mission.getDataSourceConfig())) {
        throw new ServiceException("没有配置数据源");
      }
      sourceConfig = JSONObject.parseObject(mission.getDataSourceConfig(), SourceConfig.class);
      if (ObjectUtils.isEmpty(sourceConfig.getStatus()) || !sourceConfig.getStatus()) {
        throw new ServiceException("DATA配置错误.");
      }
    }
    else {
      if (StringUtils.isEmpty(mission.getRefererSourceConfig())) {
        throw new ServiceException("没有配置数据源");
      }
      sourceConfig = JSONObject.parseObject(mission.getRefererSourceConfig(),
          SourceConfig.class);
    }
    if (!sourceConfig.getStatus()) {
      throw new ServiceException("DATA 配置错误.");
    }
    if (ObjectUtils.isEmpty(sourceConfig)) {
      throw new ServiceException("数据源配置异常");
    }
    if (CollectionUtils.isEmpty(sourceConfig.getSourceCodeList())) {
      throw new ServiceException("没有配置数据源");
    }
//    if (DuplicateConditionEnum.getEnumByName(sourceConfig.getDuplicateCondition()).isCodeList()) {
//      if (CollectionUtils.isEmpty(sourceConfig.getCodeList())) {
//        throw new ServiceException("没有配置去重条件");
//      }
//    }
    return sourceConfig;
  }

  @Override
  public void checkAuthentication(String authentication) {
    if (StringUtils.isEmpty(authentication)) {
      throw new ServiceException("需要设备权限编号");
    }
    if (!redisService.hasKey(RedisKeyConstants.DEPT_ID_FOR_AUTHENTICATION.formatKey() + authentication)) {
      Integer count = clientMapper.checkAuthentication(authentication);
      if (count == 0) {
        throw new ServiceException("认证失败");
      }
    }
    //return ;
    //Integer count = clientMapper.checkAuthentication(authentication);
    //if (count == 0) {
    //
    //}
  }

  @Transactional
  @Override
  public boolean returnDataCompleteStatus(String dataSendCode, boolean success) {
    Map<String, Object> sendDetail = redisService.getCacheObject(
        DATA_SEND_REDIS_KEY + dataSendCode);
    if (ObjectUtils.isEmpty(sendDetail)) {
      throw new ServiceException("dataSessionCode 无效");
    }
    if (!redisService.hasKey(MISSION_SEND_REDIS_KEY + sendDetail.get(MISSION_SEND_CODE))) {
      throw new ServiceException("任务已返回或任务已失效");
    }
    if (!redisService.redisTemplate.opsForValue()
        .setIfAbsent(DATA_SEND_CHECK_REPEAT + dataSendCode, 1, 5, TimeUnit.MINUTES)) {
      throw new ServiceException("数据回执已提交,请勿重复提交");
    }
    boolean b = true;
    try {
      if (!success) {
        //将数据变为未使用状态
        //删除获取数据时根据去重条件的锁
        String dataId = sendDetail.get(DATA_SEND_ID).toString();

        String dataType = sendDetail.get(DATA_SEND_TYPE).toString();
        String duplicateCondition = sendDetail.get(DATA_SEND_DATA_SOURCE_DUPLICATE_CONDITION).toString();
        String missionCode = sendDetail.get(DATA_SEND_MISSION_CODE).toString();
        MissionInfo missionByCode = missionService.getMissionByCode(missionCode, false);
        if(DataFileTypeEnum.DATA.name().equals(dataType)){
          if(DuplicateConditionEnum.BY_MISSION_ID.name().equals(duplicateCondition)){
            String dataLock = RedisKeyConstants.DATA_GET_LOCK.formatKey(dataId,missionByCode.getCode())  ;
            redisService.deleteObject(
                    dataLock);
          }else if(DuplicateConditionEnum.BY_AFFILIATE_ID.name().equals(duplicateCondition)){
            String dataLock = RedisKeyConstants.DATA_GET_LOCK.formatKey(dataId,missionByCode.getAffiliateCode())  ;
            redisService.deleteObject(
                    dataLock);
          }else if(DuplicateConditionEnum.BY_ADVERTISER_ID.name().equals(duplicateCondition)){
            String dataLock = RedisKeyConstants.DATA_GET_LOCK.formatKey(dataId,missionByCode.getAdvertiserCode())  ;
            redisService.deleteObject(
                    dataLock);
          }




          String sourceCode = sendDetail.get(DATA_SEND_DATA_SOURCE_CODE).toString();

          //如果慢下面所有的操作都放到缓存中定时任务获取执行
          //数据失败表+1
          Long tableSuf = Long.valueOf(dataId) % 20 +1;
          dataOperationService.dataUseFailedIncrement(
                  missionCode, sendDetail.get(DATA_SEND_CODE).toString(), tableSuf.toString(), dataType
          );
          String dataSendTime = sendDetail.get(DATA_SEND_TIME).toString();
          //删除索引表
          String historyCode = sendDetail.get(DATA_SEND_INDEX_TABLE_CODE).toString();

          dataOperationService.deleteHistoryDataGetIndex(historyCode, dataSendTime);
          //删除关联表数据
          dataOperationInfoService.updateRelationData(historyCode,dataId,dataType);
          //更新预计算表
          dataPreAvailableService.updatePreAvailableDataIncrease(duplicateCondition,sourceCode,missionByCode,dataType);
          //修改发送详情表使用状态
          dataOperationService.updateHistoryDataGetDetail(historyCode, false, dataSendTime);
          if (DataFileTypeEnum.DATA.name().equals(dataType)) {
            //暂时只有datasource的数据需要加+
            missionService.decrementMissionAndSourceUseCountBySourceCode(missionCode , sendDetail.get(DATA_SEND_DATA_SOURCE_CODE).toString());
          }
        }
        //删除缓存
        redisService.deleteObject(DATA_SEND_REDIS_KEY + dataSendCode);
        }

    } catch (Exception e) {
      TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      redisService.deleteObject(DATA_SEND_CHECK_REPEAT + dataSendCode);
      b = false;
    }
    return b;
  }

  @Transactional
  @Override
  public boolean  returnMissionCompleteStatus(ClientMissionCompleteRequestDTO request) {
    String missionSendCode = request.getMissionSessionCode();
    Map<String, Object> sendDetail = redisService.getCacheObject(MISSION_SEND_REDIS_KEY + missionSendCode);
    if (ObjectUtils.isEmpty(sendDetail)) {
      throw new ServiceException("missionSessionCode 无效");
    }

    if(ObjectUtils.isEmpty(request.getPageStatus())){
      throw new ServiceException(ErrorCodeConstants.INPUT_PARAMETER_PAGESTATUS_NOT_EMPTY.getMsg());
    }

    if(!MissionPageStatusEnum.isValidInfo(request.getPageStatus())){
      throw new ServiceException(ErrorCodeConstants.INPUT_PARAMETER_PAGESTATUS_IS_ABNORMAL.getMsg());
    }
    if (!redisService.redisTemplate.opsForValue()
            .setIfAbsent(MISSION_SEND_CHECK_REPEAT + missionSendCode, 1, 5, TimeUnit.MINUTES)) {
      throw new ServiceException("数据回执已提交,请勿重复提交");
    }

    String missionCode = sendDetail.get(DATA_SEND_MISSION_CODE).toString();
    String missionSendCountHourRedisKey =
        RedisConstants.MISSION_COMPLETE_SEND_COUNT_HOUR + missionCode
            + ":" + sendDetail.get(MISSION_SEND_WEEK) + ":" + sendDetail.get(MISSION_SEND_HOUR);
    boolean b = true;
    boolean status = true;
    String dataSendTime = sendDetail.get(DATA_SEND_TIME).toString();
    try {
      String deviceType = sendDetail.get(MISSION_SEND_DEVICE_TYPE).toString();
      if (MissionPageStatusEnum.BAD.getInfo().equals(request.getPageStatus())) {
        //任务失败阈值+1,任务小时发送数量-1
        if (DeviceTypeEnum.TASKER.name().equals(deviceType)) {
          //只有普通任务类型需要做这些处理
          //任务失败次数加1
          Long failedCount = redisService.redisTemplate.opsForValue().increment(RedisConstants.MISSION_PAGE_FAILED_COUNT + missionCode);
          if (ObjectUtils.isEmpty(failedCount)) {
            failedCount = missionService.getFailedCountByMissionCode(missionCode);
            redisService.setCacheObject(RedisConstants.MISSION_PAGE_FAILED_COUNT + missionCode, failedCount);
          }
          if (failedCount >= (Long) sendDetail.get(PAGE_STATUS_THRESHOLD)) {
            //如果现在的失败次数大于设定值,就把这个任务存到任务异常的缓存中,前面获取的时候先从缓存获取,再看数据库
            redisService.redisTemplate.opsForValue().setIfAbsent(RedisConstants.MISSION_NOT_NORMAL_STATE + missionCode, 1);
          }
          //任务发送数量减1
          redisService.redisTemplate.opsForValue().decrement(missionSendCountHourRedisKey);
          redisService.expire(missionSendCountHourRedisKey, 3, TimeUnit.HOURS);
        }
        status = false;
      } else {
        //不管是检测设备还是任务设备,只要返回成功都需要重置状态
        missionService.initMissionNormalState(missionCode, true);
      }
      //删缓存
      redisService.deleteObject(MISSION_SEND_REDIS_KEY + missionSendCode);
    } catch (Exception e) {
      TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      redisService.deleteObject(MISSION_SEND_CHECK_REPEAT + missionSendCode);
      b = false;
    }
    //成功就执行成功逻辑,更新操作记录,暂时只想到有更新时间和状态
    Object missionSendDate = sendDetail.get(MISSION_SEND_DATE);
    Date createDate = new Date();
    if (!ObjectUtils.isEmpty(missionSendDate)) {
      createDate = (Date) missionSendDate;
    }
    dataOperationService.updateHistoryMissionGetDetail(missionSendCode, dataSendTime, status, request, createDate);
    //Object missionSendDeviceCode = sendDetail.get(MISSION_SEND_DEVICE_CODE);
    //if (!ObjectUtils.isEmpty(missionSendDeviceCode)) {
    //  redisService.deleteObject(DEVICE_GET_LOCK + missionSendDeviceCode.toString());
    //}
    return b;
  }

  @Override
  public void returnDeviceCompleteStatus(String deviceCode) {
    redisService.deleteObject(DEVICE_GET_LOCK + deviceCode);
  }

  //@Override
  //public boolean returnMissionScriptExecuteStatus(String missionSendCode, boolean success) {
  //  Map<String, Object> sendDetail = redisService.getCacheObject(MISSION_SEND_REDIS_KEY + missionSendCode);
  //  if (ObjectUtils.isEmpty(sendDetail)) {
  //    throw new ServiceException("missionSessionCode 无效");
  //  }
  //  if (!redisService.redisTemplate.opsForValue()
  //      .setIfAbsent(MISSION_SEND_CHECK_REPEAT + missionSendCode, 1, 5, TimeUnit.MINUTES)) {
  //    throw new ServiceException("数据回执已提交,请勿重复提交");
  //  }
  //  String missionCode = sendDetail.get(DATA_SEND_MISSION_CODE).toString();
  //  String missionSendCountHourRedisKey =
  //      RedisConstants.MISSION_COMPLETE_SEND_COUNT_HOUR + missionCode
  //          + ":" + sendDetail.get(MISSION_SEND_WEEK) + ":" + sendDetail.get(MISSION_SEND_HOUR);
  //  boolean b = true;
  //  try {
  //    String deviceType = sendDetail.get(MISSION_SEND_DEVICE_TYPE).toString();
  //    String dataSendTime = sendDetail.get(DATA_SEND_TIME).toString();
  //    if (!success) {
  //      //任务失败阈值+1,任务小时发送数量-1
  //      if (DeviceTypeEnum.TASKER.name().equals(deviceType)) {
  //        //只有普通任务类型需要做这些处理
  //        //任务失败次数加1
  //        Long failedCount = redisService.redisTemplate.opsForValue().increment(RedisConstants.MISSION_FAILED_COUNT + missionCode);
  //        if (ObjectUtils.isEmpty(failedCount)) {
  //          failedCount = missionService.getFailedCountByMissionCode(missionCode);
  //          redisService.setCacheObject(RedisConstants.MISSION_FAILED_COUNT + missionCode, failedCount);
  //        }
  //        if (failedCount > (Long) sendDetail.get(PAGE_STATUS_THRESHOLD)) {
  //          //如果现在的失败次数大于设定值,就把这个任务存到任务异常的缓存中,前面获取的时候先从缓存获取,再看数据库
  //          redisService.redisTemplate.opsForValue().setIfAbsent(RedisConstants.MISSION_NOT_NORMAL_STATE + missionCode, 1);
  //        }
  //        //任务发送数量减1
  //        redisService.redisTemplate.opsForValue().decrement(missionSendCountHourRedisKey);
  //        redisService.expire(missionSendCountHourRedisKey, 3, TimeUnit.HOURS);
  //      }
  //      dataOperationService.updateHistoryMissionGetDetail(missionSendCode, dataSendTime, false);
  //    } else {
  //      //成功就执行成功逻辑,更新操作记录,暂时只想到有更新时间和状态
  //      dataOperationService.updateHistoryMissionGetDetail(missionSendCode, dataSendTime, true);
  //      //不管是检测设备还是任务设备,只要返回成功都需要重置状态
  //      missionService.initMissionNormalState(missionCode, true);
  //    }
  //    //删缓存
  //    redisService.deleteObject(MISSION_SEND_REDIS_KEY + missionSendCode);
  //  } catch (Exception e) {
  //    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  //    redisService.deleteObject(MISSION_SEND_CHECK_REPEAT + missionSendCode);
  //    b = false;
  //  }
  //  return b;
  //}

  private DataAvailableDataInfo getCanUseDataId(SourceConfig sourceConfig,
      MissionInfo missionByCode, String dataType, List<String> indexTableNameList,
      Map<String, Object> sendDataMap) {
    DataAvailableDataInfo canUseSendData = null;
    //通过数据源获取可以使用资料的子表的后缀
    if (DataFileTypeEnum.DATA.name().equals(dataType)) {
      canUseSendData = getCanUseSendData(sourceConfig, missionByCode, dataType, sendDataMap, SystemFunctionUtil.TABLE_PREFIX_INFO, SystemFunctionUtil.RELATION_MISSION_DATA_PREFIX);
      return canUseSendData;
    }
//    }else if(DataFileTypeEnum.REFERER.name().equals(dataType)){
//      DataOperationInfo canUseSendRefere = dataPreAvailableService.getCanUseSendRefere(sourceConfig);
//      if(ObjectUtils.isEmpty(canUseSendRefere)){
//        throw new ServiceException(ErrorCodeConstants.NO_DATA_SOURCES_REFEREAVAILABLE.getMsg());
//      }
//      canUseSendData  = new DataAvailableDataInfo();
//      canUseSendData.setDataOperationInfo(canUseSendRefere);
//      return canUseSendData;
//    }
    return null;
  }

  private DataAvailableDataInfo getCanUseSendData(SourceConfig sourceConfig, MissionInfo missionByCode, String dataType, Map<String, Object> sendDataMap, String dataTablePre, String relataionTablePre) {
    DataAvailableDataInfo dataAvailableDataInfo = new DataAvailableDataInfo();
    List<String> sourceCodeList = sourceConfig.getSourceCodeList();
    //按照任务去重
    DataOperationInfo dataOperationInfo = null;
    String duplicateDataValue="";

    //初始化资料表后缀
    List<Integer> tableSuff = Arrays.asList(
            1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
            11, 12, 13, 14, 15, 16, 17, 18, 19, 20
    );
    // 打乱列表以实现随机
    Collections.shuffle(tableSuff);


    if(DuplicateConditionEnum.BY_MISSION_ID.name()
            .equals(sourceConfig.getDuplicateCondition())){

              // 获取可以使用的资料
              dataOperationInfo = getDataOperationInfo(missionByCode, sourceCodeList, dataOperationInfo, tableSuff,DuplicateConditionEnum.BY_MISSION_ID.name());

              // 如果20张分表扫完都没有找到数据，向该条任务插入问题
              if(ObjectUtils.isEmpty(dataOperationInfo)){
                QuestionShowInfo missionQuestion = questionInfoService.getQuestionInfosByMissionTypeAndCode(QuestionInfoTypeEnum.MISSION.name(), missionByCode.getCode());

                if(ObjectUtils.isEmpty(missionQuestion)){
                  questionInfoService.insertQuestionByTypeIsMission(missionByCode.getCode());
                }else {
                  questionInfoService.updatetQuestionByTypeIsMission(missionQuestion.getCode());
                }

                throw new ServiceException(ErrorCodeConstants.NO_DATA_SOURCES_AVAILABLE.getMsg());
              }

              dataAvailableDataInfo.setDataOperationInfo(dataOperationInfo);
              dataAvailableDataInfo.setDuplicateCondition(DuplicateConditionEnum.BY_MISSION_ID.name());

              duplicateDataValue = RedisKeyConstants.DATA_GET_LOCK.formatKey(dataOperationInfo.getId(),missionByCode.getCode())  ;

              if (!redisService.redisTemplate.opsForValue()
                      .setIfAbsent(duplicateDataValue, 1, 5, TimeUnit.MINUTES)) {

                throw new ServiceException(ErrorCodeConstants.DATA_IS_USING.getMsg());
              }

      //按照联盟主去重
      } else if(DuplicateConditionEnum.BY_AFFILIATE_ID.name()
            .equals(sourceConfig.getDuplicateCondition())){

            dataOperationInfo = getDataOperationInfo(missionByCode, sourceCodeList,  dataOperationInfo, tableSuff, DuplicateConditionEnum.BY_AFFILIATE_ID.name());

            // 如果20张分表扫完都没有找到数据，向该条任务插入问题
            if(ObjectUtils.isEmpty(dataOperationInfo)){
              QuestionShowInfo missionQuestion = questionInfoService.getQuestionInfosByMissionTypeAndCode(QuestionInfoTypeEnum.MISSION.name(), missionByCode.getCode());

              if(ObjectUtils.isEmpty(missionQuestion)){
                questionInfoService.insertQuestionByTypeIsMission(missionByCode.getCode());
              }else {
                questionInfoService.updatetQuestionByTypeIsMission(missionQuestion.getCode());
              }

              throw new ServiceException(ErrorCodeConstants.NO_DATA_SOURCES_AVAILABLE.getMsg());

            }

              dataAvailableDataInfo.setDataOperationInfo(dataOperationInfo);
              dataAvailableDataInfo.setDuplicateCondition(DuplicateConditionEnum.BY_AFFILIATE_ID.name());

            duplicateDataValue = RedisKeyConstants.DATA_GET_LOCK.formatKey(dataOperationInfo.getId(),missionByCode.getAffiliateCode())  ;
              if (!redisService.redisTemplate.opsForValue()
                      .setIfAbsent(duplicateDataValue, 1, 5, TimeUnit.MINUTES)) {
                throw new ServiceException(ErrorCodeConstants.DATA_IS_USING.getMsg());
              }
      //按照广告主去重
      } else if(DuplicateConditionEnum.BY_ADVERTISER_ID.name()
            .equals(sourceConfig.getDuplicateCondition())){
            dataOperationInfo = getDataOperationInfo(missionByCode, sourceCodeList,  dataOperationInfo, tableSuff, DuplicateConditionEnum.BY_ADVERTISER_ID.name());

             // 如果20张分表扫完都没有找到数据，向该条任务插入问题
            if(ObjectUtils.isEmpty(dataOperationInfo)){
              QuestionShowInfo missionQuestion = questionInfoService.getQuestionInfosByMissionTypeAndCode(QuestionInfoTypeEnum.MISSION.name(), missionByCode.getCode());

              if(ObjectUtils.isEmpty(missionQuestion)){
                questionInfoService.insertQuestionByTypeIsMission(missionByCode.getCode());
              }else {
                questionInfoService.updatetQuestionByTypeIsMission(missionQuestion.getCode());
              }
              throw new ServiceException(ErrorCodeConstants.NO_DATA_SOURCES_AVAILABLE.getMsg());
            }

              dataAvailableDataInfo.setDataOperationInfo(dataOperationInfo);
              dataAvailableDataInfo.setDuplicateCondition(DuplicateConditionEnum.BY_ADVERTISER_ID.name());

            duplicateDataValue = RedisKeyConstants.DATA_GET_LOCK.formatKey(dataOperationInfo.getId(),missionByCode.getAdvertiserCode())  ;
              if (!redisService.redisTemplate.opsForValue()
                      .setIfAbsent(duplicateDataValue, 1, 5, TimeUnit.MINUTES)) {
                throw new ServiceException(ErrorCodeConstants.DATA_IS_USING.getMsg());
              }

      }

    Integer failedCount = dataSendByMissionService.getFailedCount(missionByCode.getCode(), dataOperationInfo.getCode());

    boolean resultFlag =
            ObjectUtils.isEmpty(failedCount) || failedCount < missionByCode.getLimitationCount();
    if (resultFlag) {
      sendDataMap.put(ClientServiceImpl.DATA_GET_LOCK_VALUE, duplicateDataValue);
    }

    sourceConfig.setChooseCode(dataOperationInfo.getDataSourceCode());
    return dataAvailableDataInfo;

  }

  private DataOperationInfo getDataOperationInfo(MissionInfo missionByCode, List<String> sourceCodeList, DataOperationInfo dataOperationInfo, List<Integer> tableSuff, String duplicateName) {

    for (Integer integer : tableSuff) {
      String dataTableName = SystemFunctionUtil.TABLE_PREFIX_INFO + integer.intValue();
      String relationTableName = SystemFunctionUtil.RELATION_MISSION_DATA_PREFIX + integer.intValue();

      dataOperationInfo = dataOperationInfoService.getCanUseSendData(
              dataTableName,
              relationTableName,
              sourceCodeList,
              missionByCode.getCode(),
              missionByCode.getAffiliateCode(),
              missionByCode.getAdvertiserCode()
      );

      if(!ObjectUtils.isEmpty(dataOperationInfo)){
        log.info("读取的表名为:"+integer+"数据内容为："+dataOperationInfo);
        break;
      }
    }

    return dataOperationInfo;
  }


  private boolean checkDataCanUse(String code, String redisKey, MissionInfo missionByCode,
      String dataType, SourceConfig sourceConfig, List<String> indexTableNameList,
      Map<String, Object> sendDataMap) {
    //boolean flag = redisService.redisTemplate.opsForValue()
    //    .setIfAbsent(redisKey + code, 1, 5, TimeUnit.MINUTES);
    boolean missionCheck = true;
    if (DataFileTypeEnum.DATA.name().equals(dataType)) {
      missionCheck = missionService.getDataCanSend(code, missionByCode, sourceConfig, indexTableNameList, sendDataMap);
    }
    //return (flag && missionCheck);
    return missionCheck;
  }

  @Override
  public MissionOperationResponseDTO getMissionByDeviceCode(MissionGetRequestDTO request) {
    //验证设备状态和authentication
    canGet(request);
    //能通过就是正常请求
    //获取设备信息
    //todo 这里也可以改为从缓存中获取
    DeviceInfo deviceInfo = deviceService.getDeviceByCode(request.getDeviceCode());
    List<String> canUseEngineCode = deviceService.getCanUseEngineCodesByDeviceCode(request.getDeviceCode());
    if (CollectionUtils.isEmpty(canUseEngineCode)) {
      throw new ServiceException("设备无支持引擎");
    }
    if (ObjectUtils.isEmpty(deviceInfo)) {
      throw new ServiceException("deviceCode 无效");
    }
    //获取设备存在哪些分组中
    DeviceGroupInfo groupInfos = deviceGroupService.getDeviceGroupByCode(deviceInfo.getDeviceGroupCode());
    //获取所有包含当前分组code的任务,检测设备获取状态为false的任务
    //2025-02-12添加的如果任务关联了有被操作过的平台数据和引擎数据和代理数据也不能被获取到
    List<MissionInfo> missionInfos = new ArrayList<>();
    if (DeviceTypeEnum.CHECKER.name().equals(deviceInfo.getDeviceType())) {
      missionInfos = missionService.getMissionListByGroupCodes(groupInfos.getCode(), null, false);
      if (CollectionUtils.isEmpty(missionInfos)) {
        throw new ServiceException("没有异常任务");
      }
    } else {
      missionInfos = missionService.getMissionListByGroupCodes(groupInfos.getCode(), deviceInfo.getDeptCode(), true);
      if (CollectionUtils.isEmpty(missionInfos)) {
        return null;
      }
    }
    //通过计划里面的限制来检查是否可以获取任务
    //星期几
    WeekEnum week = DateUtil.getWeek();
    //获取当前小时
    int currentHour = DateUtil.getCurrentHour();
    //获取当天格式化日期
    String currentDay = DateUtil.dateToStr(new Date(), DateConstants.DATE_FORMAT_NUM);
    //根据权重获取应该返回的任务
    MissionInfo missionInfo = getMissionByWeight(missionInfos, week, currentHour, currentDay,
        DeviceTypeEnum.TASKER.name().equals(deviceInfo.getDeviceType()), canUseEngineCode);
    if (ObjectUtils.isEmpty(missionInfo)) {
      return null;
    }
    //将发送记录存到redis中,方便后续使用其他关联数据,也是发送记录表code
    String missionSendCode = UUID.randomUUID().toString().replace("-", "");
    Date date = new Date();
    String dateFormat = DateUtil.dateToStr(date, DateConstants.DATE_FORMAT_YM);
    String dateFormatYmdHms = DateUtil.dateToStr(date, DateConstants.DATE_TIME_FORMAT_NUM);
    //获取任务详情
    MissionInfo missionByCode = missionService.getMissionByCode(missionInfo.getCode(), true);
    missionByCode.setEngineInfo(missionInfo.getEngineInfo());
//    setMissionDataSource(missionByCode);
    Map<String, Object> sendMissionMap = new HashMap<>();
    sendMissionMap.put(MISSION_SEND_WEEK, week.name());
    sendMissionMap.put(MISSION_SEND_HOUR, currentHour);
    sendMissionMap.put(MISSION_SEND_DAY, currentDay);
    sendMissionMap.put(MISSION_SEND_DATE, date);
    sendMissionMap.put(MISSION_SEND_MISSION_CODE, missionInfo.getCode());
    sendMissionMap.put(MISSION_SEND_DEVICE_CODE, request.getDeviceCode());
    sendMissionMap.put(MISSION_SEND_MISSION_ID, missionInfo.getId());
    sendMissionMap.put(PAGE_STATUS_THRESHOLD, missionInfo.getPageStatusThreshold());
    sendMissionMap.put(MISSION_SEND_CODE, missionSendCode);
    sendMissionMap.put(DATA_SEND_TIME, dateFormat);
    sendMissionMap.put(MISSION_SEND_DEVICE_TYPE, deviceInfo.getDeviceType());
    sendMissionMap.put(DATA_SEND_MISSION_NAME, missionInfo.getMissionName());
    redisService.setCacheObject(MISSION_SEND_REDIS_KEY + missionSendCode, sendMissionMap, 30,
        TimeUnit.MINUTES);
    dataOperationService.insertMissionGetHistory(missionSendCode, missionByCode, deviceInfo,
        dateFormat, dateFormatYmdHms);
    //国家
    CountryInfo countryInfo = redisService.getCacheObject(RedisKeyConstants.COUNTRY_INFO.formatKey(missionInfo.getCountryCode()));
    return new MissionOperationResponseDTO(missionByCode, missionSendCode, countryInfo);
  }

  private void setMissionDataSource(MissionInfo missionByCode) {
    if(missionByCode!=null){
      if(!ObjectUtils.isEmpty(missionByCode.getDataSourceConfig())){
        SourceConfig sourceConfig = JSONObject.parseObject(missionByCode.getDataSourceConfig(), SourceConfig.class);
        MissionData missionData = new MissionData();
        missionData.setStatus(sourceConfig.getStatus());
        missionData.setDuplicateCondition(sourceConfig.getDuplicateCondition());
        List<String> sourceCodeList = sourceConfig.getSourceCodeList();
        List<DatasourceInfo> dataSourceInfo = datasourceService.getDataSourceByCodes(sourceCodeList);
        String [] dataSource=new String[dataSourceInfo.size()];
        for (int i = 0; i < dataSourceInfo.size(); i++) {
          dataSource[i]=dataSourceInfo.get(i).getDatasourceName();
        }
        missionData.setDataSourceInfos(dataSource);
        missionByCode.setDataSource(missionData);
      }

      if(!ObjectUtils.isEmpty(missionByCode.getRefererSourceConfig())){
        SourceConfig sourceConfig = JSONObject.parseObject(missionByCode.getRefererSourceConfig(), SourceConfig.class);
        MissionData missionReferer = new MissionData();
        List<RefererSourceInfo> dataSourceInfo = refererSourceService.getRefererSourceByCodes(sourceConfig.getSourceCodeList());
        String [] refererSource=new String[dataSourceInfo.size()];
        for (int i = 0; i < dataSourceInfo.size(); i++) {
          refererSource[i]= dataSourceInfo.get(i).getRefererSourceName();
        }
        missionReferer.setStatus(sourceConfig.getStatus());
        missionReferer.setDataSourceInfos(refererSource);
        missionByCode.setRefererSource(missionReferer);
      }

    }

  }

  private MissionInfo  getMissionByWeight(List<MissionInfo> missionInfos, WeekEnum week,
      int currentHour, String currentDay, boolean tasker, List<String> canUseEngineCode) {
    if (CollectionUtils.isEmpty(missionInfos)) {
      return null;
    }
    MissionInfo missionInfo = null;
    List<Entry<String>> entriesList = new ArrayList<>();
    int sum = missionInfos.stream().mapToInt(MissionInfo::getWeight).sum();
    if (sum == 0) {
      missionInfos.forEach(f -> {
        entriesList.add(new Entry<>(f.getCode(), 1));
      });
    } else {
      missionInfos.forEach(f -> {
        entriesList.add(new Entry<>(f.getCode(), f.getWeight()));
      });
    }
    WeightedRandomSelector<String> selector = new WeightedRandomSelector<>(entriesList);
    String selectCode = selector.select();
    MissionInfo mission = missionInfos.stream().filter(f -> selectCode.equals(f.getCode()))
        .findFirst().orElse(null);
    if (!tasker) {
      return mission;
    }
    if (!ObjectUtils.isEmpty(mission)) {
      //检查是否超过计划里面的阈值
      if (!checkMissionOverPlanAndEngineSchemeIncludeDeviceEngine(mission, week, currentHour, currentDay,canUseEngineCode)) {
        missionInfos.removeIf(f -> f.getCode().equals(mission.getCode()));
        missionInfo = getMissionByWeight(missionInfos, week, currentHour, currentDay, tasker, canUseEngineCode);
      } else {
        missionInfo = mission;
      }
    }
    return missionInfo;
  }

  private boolean checkMissionEngineSchemeIncludeDeviceEngin(MissionInfo missionInfo, List<String> canUseEngineCode) {

    if(StringUtils.isEmpty(missionInfo.getBrowserEnginesConfigCode())){
      return false;
    }

    List<RelationEngineAndSchemeInfo> relation = engineSchemeService.getEngineAndEngineSchemeRelation(missionInfo.getBrowserEnginesConfigCode());
    if(CollectionUtils.isEmpty(relation)){
      return false;
    }

    List<String> engineCodes = getEngineCode(relation, canUseEngineCode);
    if(CollectionUtils.isEmpty(engineCodes)){
      return false;
    }

    List<EngineInfo> engineInfos = new ArrayList<>();
    for (String engineCode : engineCodes) {
      EngineInfo engineByCode = engineService.getEngineByCode(engineCode);
      engineInfos.add(engineByCode);
    }

    if (CollectionUtils.isEmpty(engineInfos)){
      return false;
    }

    missionInfo.setEngineInfo(engineInfos);
    return  true;
  }

  private List<String> getEngineCode(List<RelationEngineAndSchemeInfo> missionEngineConfigs, List<String> canUseEngineCode) {

    List<String> clientEnginCode = new ArrayList<>();
    int configWeightSum = missionEngineConfigs.stream().mapToInt(RelationEngineAndSchemeInfo::getWeight).sum();
    List<Entry<String>> engineCodes = new ArrayList<>();
    if (configWeightSum == 0) {
      missionEngineConfigs.forEach(f -> {
        engineCodes.add(new Entry<>(f.getEngineCode(), 1));
      });
    } else {
      missionEngineConfigs.forEach(f -> {
        engineCodes.add(new Entry<>(f.getEngineCode(), f.getWeight()));
      });
    }
    //设备对应下的引擎和任务下对应下的引擎之的交集
    List<Entry<String>> shareEngineCodes = engineCodes.stream().filter(f -> canUseEngineCode.contains(f.item)).collect(Collectors.toList());

    //交集随机选择一条后，移除该条并在剩余中选择一条

    if(!ObjectUtils.isEmpty(shareEngineCodes)){
      while (shareEngineCodes.size()>0){
        if(shareEngineCodes.size() == 1 ){
          shareEngineCodes.get(0).weight=1;
        }
        WeightedRandomSelector<String> engineSelector = new WeightedRandomSelector<>(shareEngineCodes);
        String selectEngineCode = engineSelector.select();
        clientEnginCode.add(selectEngineCode);
        shareEngineCodes.removeIf(f -> f.item.equals(selectEngineCode));
      }
    }


    return clientEnginCode;
  }

  private boolean checkMissionOverPlanAndEngineSchemeIncludeDeviceEngine(MissionInfo missionInfo, WeekEnum week, int currentHour,
                                                                         String currentDay, List<String> canUseEngineCode) {
    //先检查任务是否处于异常状态,因为在获取数据的时候就已经sql中判断过非异常状态,这里只需要判断是否存在缓存中就行
    if(redisService.hasKey(RedisConstants.MISSION_NOT_NORMAL_STATE + missionInfo.getCode())) {
      return false;
    }
    PlanInfo planByCode = planService.getPlanByCode(missionInfo.getPlanCode());
    if (ObjectUtils.isEmpty(planByCode)) {
      throw new ServiceException("任务计划为空");
    }
    missionInfo.setPlanInfo(planByCode);
    String dataSendCountHourRedisKey =
        RedisConstants.MISSION_COMPLETE_SEND_COUNT_HOUR + missionInfo.getCode() + ":"
            + week.name() + ":" + currentHour;
    String dataSendCountDayRedisKey =
        RedisConstants.MISSION_COMPLETE_SEND_COUNT_DAY + missionInfo.getCode() + ":" + currentDay;
    //超出计划配置数量,不返回
    boolean overPlanCount = overPlanCount(planByCode, missionInfo, week, currentHour, dataSendCountHourRedisKey,
            dataSendCountDayRedisKey);
    if(!overPlanCount){
      return overPlanCount;
    }
    //设备引擎是否包含引擎方案下关联的引擎
    return  checkMissionEngineSchemeIncludeDeviceEngin(missionInfo, canUseEngineCode);

  }

  private void canGet(MissionGetRequestDTO request) {
    Integer deviceCount = deviceService.checkDevice(request.getDeviceCode());
    if (deviceCount == 0) {
      throw new ServiceException("未知设备或设备类型错误");
    }
  }


  private boolean overPlanCount(PlanInfo planByCode, MissionInfo missionByCode, WeekEnum week,
      int currentHour, String redisKey, String dataSendCountDayRedisKey) {
    boolean flag = true;
    String optionJson = SystemFunctionUtil.getPlanDayJson(planByCode, week);
    if (StringUtils.isEmpty(optionJson)) {
      return false;
    }
    List<PlanJsonConfig> planJsonConfig = JSONArray.parseArray(optionJson, PlanJsonConfig.class);
    PlanJsonConfig planJsonByHour = planJsonConfig.stream().filter(f -> f.getHour() == currentHour)
        .findFirst().orElse(null);
    if (ObjectUtils.isEmpty(planJsonByHour) || ObjectUtils.isEmpty(planJsonByHour.getHour())
        || ObjectUtils.isEmpty(planJsonByHour.getCount())) {
      return false;
    }
    boolean hourAdd = false;
    boolean dayAdd = false;
    //redis+1,如果返回值大于设定最大值返回false,并-1回去
    try {
      Long increment = redisService.redisTemplate.opsForValue().increment(redisKey);
      hourAdd = true;
      //当天累加
      Long dayComplete = redisService.redisTemplate.opsForValue().increment(dataSendCountDayRedisKey);
      dayAdd = true;
      //具体值用百分比算出来
      BigDecimal divideNum = new BigDecimal(planJsonByHour.getCount()).divide(new BigDecimal(100),
          2, RoundingMode.HALF_UP);
      //限制总数
      BigDecimal allCount = new BigDecimal(missionByCode.getLimitationCount());
      //当前小时最多能获取多少次
      BigDecimal hourCount = new BigDecimal(missionByCode.getLimitationCount()).multiply(divideNum)
          .setScale(0, RoundingMode.HALF_UP);
      if (hourCount.compareTo(allCount) > 0) {
        hourCount = allCount;
      }
      if ((increment != null && BigDecimal.valueOf(increment).compareTo(hourCount) > 0) ||
          (dayComplete != null && BigDecimal.valueOf(dayComplete).compareTo(allCount) > 0)) {
        flag = false;
      }
    } catch (Exception e) {
      if (hourAdd) {
        redisService.redisTemplate.opsForValue().decrement(redisKey);
        hourAdd= false;
      }
      if (dayAdd) {
        redisService.redisTemplate.opsForValue().decrement(dataSendCountDayRedisKey);
        dayAdd = false;
      }
      flag = false;
    } finally {
      //发一个就直接+1的原因是完全不允许超发,任务返回成功不-返回失败才-掉名额,可以少发不能多发
      if (!flag) {
        if (hourAdd) {
          redisService.redisTemplate.opsForValue().decrement(redisKey);
        }
        if (dayAdd) {
          redisService.redisTemplate.opsForValue().decrement(dataSendCountDayRedisKey);
        }
      }


      redisService.expire(redisKey, 3, TimeUnit.HOURS);
      redisService.expire(dataSendCountDayRedisKey, 25, TimeUnit.HOURS);
    }
    return flag;
  }

}
